package houxb.cn;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;

import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class JGitClient {
    private static final Map<String, String> SOURCE_TO_TARGET = new HashMap<>() {{
        put("src/main/java", "pmcore/WEB-INF/classes");
        put("src/license/src", "pmcore/WEB-INF/classes");
        put("src/main/resources", "pmcore/WEB-INF/classes");
        put("src/main/webapp", "pmcore");
    }};

    /**
     * 根据修改记录获取编译后文件
     *
     * @param gitPath      git目录
     * @param startVersion 开始版本（不包含）
     * @param endVersion   结束版本（包含）
     * @param targetPath   目标目录
     */
    public static void history(String gitPath, String startVersion, String endVersion, String targetPath) {
        Set<String> paths = new HashSet<>();
        Set<String> removes = new HashSet<>();
        long s = System.currentTimeMillis();
        // 获取所有的修改路径
        try (Git git = Git.open(new File(gitPath))) {
            Repository repository = git.getRepository();
            ObjectId start = repository.resolve(startVersion);
            ObjectId end = repository.resolve(endVersion);
            Iterable<RevCommit> commits = git.log().addRange(start, end).call();
            for (RevCommit commit : commits) {
                log.info("Commit ID: {}", commit.getId().getName());
                log.info("Author: {}", commit.getAuthorIdent().getName());
                log.info("Date: {}", commit.getAuthorIdent().getWhen());
                log.info("Message: {}", commit.getFullMessage());
                log.info("Modified Paths Length:");
                RevTree preTree = null;
                if (commit.getParentCount() > 0) {
                    preTree = commit.getParent(0).getTree();
                }
                // 获取差异信息
                try (DiffFormatter diffFormatter = new DiffFormatter(System.out)) {
                    diffFormatter.setRepository(git.getRepository());
                    List<DiffEntry> diffs = diffFormatter.scan(preTree, commit.getTree());
                    log.info("\t" + diffs.size());
                    for (DiffEntry diff : diffs) {
                        if (!DiffEntry.ChangeType.DELETE.equals(diff.getChangeType())) {
                            paths.add(diff.getNewPath());
                            if (DiffEntry.ChangeType.RENAME.equals(diff.getChangeType())) {
                                removes.add(diff.getOldPath());
                            }
                        } else {
                            removes.add(diff.getOldPath());
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("获取Git日志内容异常！");
        }
        paths.removeAll(removes);
        Set<String> notFound = new HashSet<>();
        paths.forEach(path -> {
            if (path == null || path.startsWith("src/test/java")) {
                return;
            }
            int dirIndex = path.lastIndexOf("/");
            String p, fileName;
            if (dirIndex <= 0) {
                p = "";
                fileName = path;
            } else {
                p = path.substring(0, dirIndex);
                fileName = path.substring(dirIndex + 1);
            }
            int fileIndex = fileName.lastIndexOf(".");
            if (fileIndex <= 0) {
                return;
            }
            final String f = fileName.substring(0, fileIndex);
            final String ext = fileName.substring(fileIndex + 1);
            final String tmp = p;
            Map.Entry<String, String> trans = SOURCE_TO_TARGET.entrySet().stream().filter(entry -> tmp.startsWith(entry.getKey())).findFirst().orElse(null);
            if (trans != null) {
                p = p.replaceAll(trans.getKey(), trans.getValue());
            }
            final String dirPath = p;
            String dir = gitPath + "/target/" + dirPath;
            // 要搜索的目录
            File directory = new File(dir);
            if (!directory.isDirectory()) {
                notFound.add(dir);
                return;
            }
            // 模糊匹配的模式，例如 "*.txt" 匹配所有 txt 文件 (MyClass(\\$.+)?)\\.class$
            String patternString = "^(" + f + "(\\$.+)?)\\.class$";
            Pattern pattern = Pattern.compile(patternString);
            File[] files = directory.listFiles((file) -> {
                if ("java".equals(ext)) {
                    Matcher matcher = pattern.matcher(file.getName());
                    return matcher.matches();
                }
                return (f + "." + ext).equals(file.getName());
            });
            if (files == null) {
                return;
            }
            log.info("目录：{}，文件名：{}，后缀：{}", dirPath, f, ext);
            Arrays.stream(files).forEach(file -> {
                FileUtil.copy(file, new File(targetPath + dirPath + "/" + file.getName()), true);
            });
        });
        log.info("总计耗时：{}ms", System.currentTimeMillis() - s);
        log.error("目录（" + JSON.toJSONString(notFound) + "）未找到！");
    }
}